﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using XamlingCore.SL.Controls.ContentTemplate.Interfaces;

namespace XamlingCore.SL.Controls.Content
{
    [TemplateVisualState(GroupName = "ContentStates", Name = "Normal")]
    [TemplateVisualState(GroupName = "ContentStates", Name = "NormalReverse")]
    [TemplateVisualState(GroupName = "ContentStates", Name = "BeforeTransition")]
    [TemplateVisualState(GroupName = "ContentStates", Name = "BeforeTransitionReverse")]
    [TemplateVisualState(GroupName = "ContentStates", Name = "NoContent")]
    [TemplatePart(Name = "contentPresenter", Type = typeof(ContentPresenter))]
    [TemplatePart(Name = "oldContentPresenter", Type = typeof(ContentPresenter))]
    public class XTransitionContentControl : XContentControl
    {
        private ContentPresenter contentPresenter;
        private ContentPresenter oldContentPresenter;

        private bool templateApplied;

        private bool catchupApplyContent;
        private object catchUpContentObject;

        public XTransitionContentControl()
        {
            DefaultStyleKey = typeof (XTransitionContentControl);
        }

        public bool TransitionsEnabled
        {
            get { return (bool)GetValue(TransitionsEnabledProperty); }
            set { SetValue(TransitionsEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TransitionsEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TransitionsEnabledProperty =
            DependencyProperty.Register("TransitionsEnabled", typeof(bool), typeof(XTransitionContentControl), new PropertyMetadata(true));



        public IContentTemplateSelector TemplateSelector
        {
            get { return (IContentTemplateSelector)GetValue(TemplateSelectorProperty); }
            set { SetValue(TemplateSelectorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TemplateSelector.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TemplateSelectorProperty =
            DependencyProperty.Register("TemplateSelector", typeof(IContentTemplateSelector), typeof(XTransitionContentControl), null);



        public IContentCustomAnimation CustomAnimation
        {
            get { return (IContentCustomAnimation)GetValue(CustomAnimationProperty); }
            set { SetValue(CustomAnimationProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CustomAnimation.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CustomAnimationProperty =
            DependencyProperty.Register("CustomAnimation", typeof(IContentCustomAnimation), typeof(XTransitionContentControl), null);



        public bool ReverseTransition
        {
            get { return (bool)GetValue(ReverseTransitionProperty); }
            set { SetValue(ReverseTransitionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ReverseTransition.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ReverseTransitionProperty =
            DependencyProperty.Register("ReverseTransition", typeof(bool), typeof(XTransitionContentControl), new PropertyMetadata(false));



        public override void OnApplyTemplate()
        {
            ContentPresenter = this.GetTemplateChild("contentPresenter") as ContentPresenter;
            OldContentPresenter = this.GetTemplateChild("oldContentPresenter") as ContentPresenter;

            base.OnApplyTemplate();
            VisualStateManager.GoToState(this, "NoContent", false);

            templateApplied = true;
            //if (catchupApplyContent)
            //{
            //    catchupApplyContent = false;
            //    doContentChanged(null, catchUpContentObject);
            //}
        }
        protected override void OnContentChanged(object oldContent, object newContent)
        {
            ApplyTemplate();
            doContentChanged(oldContent, newContent);
        }

        private bool firstRun = true;

        void doContentChanged(object oldContent, object newContent)
        {
            if (newContent == oldContent)
            {
                return;
            }

            //only do the switch when the old and new content presenters are both present
            //otherwise act as a normal content control
            if (!firstRun && oldContentPresenter != null && contentPresenter != null)
            {

                var tempOld = oldContentPresenter;
                var tempNew = contentPresenter;
                oldContentPresenter = tempNew;
                contentPresenter = tempOld;
                if (oldContentPresenter != null && contentPresenter != null)
                {
                    var firstChild = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;

                    foreach (VisualStateGroup i in VisualStateManager.GetVisualStateGroups(firstChild))
                    {
                        foreach (VisualState state in i.States)
                        {
                            if (state.Storyboard != null)
                            {
                                state.Storyboard.Stop();
                                foreach (var timeLine in state.Storyboard.Children)
                                {
                                    var targetName = timeLine.GetValue(Storyboard.TargetNameProperty).ToString();
                                    if (targetName == oldContentPresenter.Name)
                                    {
                                        timeLine.SetValue(Storyboard.TargetNameProperty, contentPresenter.Name);
                                    }
                                    else
                                    {
                                        timeLine.SetValue(Storyboard.TargetNameProperty, oldContentPresenter.Name);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            
            if (newContent == null || (newContent is bool && !(bool)newContent))
            {
                if (firstRun)
                {
                    if (oldContentPresenter != null)
                    {
                        oldContentPresenter.Content = oldContent;
                    }
                }

                if (contentPresenter != null)
                {
                    contentPresenter.Content = newContent;
                }

                if (CustomAnimation == null)
                {
                    VisualStateManager.GoToState(this, "NoContent", TransitionsEnabled);
                }
            }
            else
            {
                if (CustomAnimation == null && !firstRun)
                {
                    if (ReverseTransition)
                    {
                        VisualStateManager.GoToState(this, "BeforeTransitionReverse", false);
                    }
                    else
                    {
                        VisualStateManager.GoToState(this, "BeforeTransition", false);
                    }
                }
                if (firstRun)
                {
                    if (oldContentPresenter != null)
                    {
                        if (TemplateSelector != null)
                        {
                            var template = TemplateSelector.SelectTemplate(oldContent);

                            if (template == null)
                            {
                                template = ContentTemplate;
                            }

                            oldContentPresenter.ContentTemplate = template;
                        }

                        //oldContentPresenter.Content = oldContent;
                    }
                }

                if (contentPresenter != null)
                {

                    if(newContent != contentPresenter.Content)
                    {
                        contentPresenter.Content = newContent;
                        if (TemplateSelector != null)
                        {
                            var template = TemplateSelector.SelectTemplate(newContent);

                            if (template == null)
                            {
                                template = ContentTemplate;
                            }

                            contentPresenter.ContentTemplate = template;
                        }
                    }
                }
                if (CustomAnimation == null)
                {
                    Dispatcher.BeginInvoke(() =>
                                               {
                                                   if (ReverseTransition)
                                                   {
                                                       VisualStateManager.GoToState(this, "NormalReverse", TransitionsEnabled);
                                                   }
                                                   else
                                                   {
                                                       VisualStateManager.GoToState(this, "Normal", TransitionsEnabled);
                                                   }
                                               });


                  
                }

            }
            base.OnContentChanged(oldContent, newContent);

            if (CustomAnimation != null)
            {
                CustomAnimation.Animate(this, contentPresenter, oldContentPresenter, ReverseTransition);
            }
            firstRun = false;
        }


        public ContentPresenter ContentPresenter
        {
            get { return contentPresenter; }
            set { contentPresenter = value; }
        }

        public ContentPresenter OldContentPresenter
        {
            get { return oldContentPresenter; }
            set { oldContentPresenter = value; }
        }

    }


}
